package com.aggregate.pay.pufa.support;

import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

import com.aggregate.pay.pufa.bean.ReqData;
import com.aggregate.pay.pufa.bean.ReqHeadData;
import com.aggregate.pay.pufa.bean.ResData;
import com.aggregate.pay.pufa.bean.ResStatusData;
import com.aggregate.pay.pufa.support.utils.JSON;
import com.fasterxml.jackson.core.type.TypeReference;

/**
 * 浦发代付接口API操作类抽象类
 * @author Moyq5
 * @date 2019年1月3日
 * @param <D>
 * @param <R>
 */
public abstract class AbstractClient<D, R> implements Client<D, R> {
		
	private Merch merch;
	
	public AbstractClient(Merch merch) {
		this.merch = merch;
	}
	
	@Override
	public ResData<R> execute(D reqBodyData) {
		
		ReqHeadData reqHeadData = createHeadData("90000");
		ResData<R> resData = null;
		try {
			
			String headJson = JSON.toString(reqHeadData);
			String bodyJson = "";
			String statusJson = "";
			
			String sign = Tool.rsaSign(headJson + bodyJson, merch.privateKey());
			
			ReqData<String> reqData = new ReqData<>();
			reqData.setBodyData("");
			reqData.setHeadData(reqHeadData);
			reqData.setDataSignature(sign);
			
			HttpClient client = Factory.getHttpClient();
			
			String reqBody = JSON.toString(reqData);
			String resBody = client.post(Factory.getConfig().getServerPath() + "?tranType="+ reqHeadData.getMsgType()+"&param=" + URLEncoder.encode(reqBody,"UTF-8"), reqBody);
			resData = JSON.toObject(resBody, new TypeReference<ResData<R>>(){});
			
			headJson = JSON.toString(resData.getHeadData());
			bodyJson = JSON.toString(resData.getBodyData());
			statusJson = JSON.toString(resData.getStatus());
			
			if (resData.getStatus().getResult().equals("2")) {
				return resData;
			}
			
			boolean isValid = Tool.rsaVerify(headJson + bodyJson + statusJson, resData.getDataSignature(), merch.publicKey());
			if (!isValid) {
				throw new Exception("签名有误");
			}
			
			@SuppressWarnings("unchecked")
			Map<String, String> map = (Map<String, String>)resData.getBodyData();
			
			byte[] pwd = Tool.rsaDecrypt(map.get("pwd"), merch.privateKey());
			
			reqHeadData = createHeadData(msgType());
			
			headJson = JSON.toString(reqHeadData);
			bodyJson = JSON.toString(reqBodyData);
			
			sign = Tool.rsaSign(headJson + bodyJson, merch.privateKey());
			
			bodyJson = Tool.aesEncrypt(bodyJson, pwd);
			
			reqData = new ReqData<>();
			reqData.setBodyData(bodyJson);
			reqData.setHeadData(reqHeadData);
			reqData.setDataSignature(sign);
			
			reqBody = JSON.toString(reqData);
			resBody = client.post(serverPath() +"?tranType="+ reqHeadData.getMsgType()+"&param=" + URLEncoder.encode(reqBody,"UTF-8"), reqBody);
			resData = JSON.toObject(resBody, new TypeReference<ResData<R>>(){});
			
			headJson = JSON.toString(resData.getHeadData());
			bodyJson = (String)resData.getBodyData();
			statusJson = JSON.toString(resData.getStatus());
			
			if (null != bodyJson) {
				bodyJson = bodyJson.replaceAll("\n|\r", "");
				bodyJson = Tool.aesDecrypt(bodyJson, pwd);
				
				// 达到排序目的
				R r = JSON.toObject(bodyJson, resBodyClass());
				bodyJson = JSON.toString(r);
			}
			
			if (resData.getStatus().getResult().equals("2")) {
				return resData;
			}
			
			isValid = Tool.rsaVerify(headJson + (null != bodyJson ? bodyJson:"") + statusJson, resData.getDataSignature(), merch.publicKey());
			if (!isValid) {
				throw new Exception("签名有误");
			}
			
			if (null != bodyJson) {
				R resBodyData = JSON.toObject(bodyJson, resBodyClass());
				resData.setBodyData(resBodyData);
			}
			
			return resData;
			
		} catch (SocketTimeoutException e) {
			resData = new ResData<R>();
			ResStatusData statusData = new ResStatusData();
			statusData.setResult("2");
			statusData.setStatusCode("C9999");
			statusData.setStatusMessage("请求超时");
		} catch (Exception e) {
			log.error("接口调用失败", e);
			resData = new ResData<R>();
			ResStatusData statusData = new ResStatusData();
			statusData.setResult("2");
			statusData.setStatusCode("C9999");
			statusData.setStatusMessage("本地错误：" + e.getMessage());
		}
		return resData;
	}
	
	protected String serverPath() {
		return Factory.getConfig().getServerPath();
	}

	protected abstract String msgType();

	protected abstract Class<R> resBodyClass();
	
	private ReqHeadData createHeadData(String msgType) {
		ReqHeadData reqHeadData = new ReqHeadData();
		reqHeadData.setCorpNo(merch.merchNo());
		reqHeadData.setMajorVersion("1.0");
		reqHeadData.setMinorVersion("1.0");
		reqHeadData.setMsgType(msgType);
		reqHeadData.setNotifyUrl("");
		reqHeadData.setReqDate(new SimpleDateFormat("yyyyMMdd").format(new Date()));
		reqHeadData.setReqTime(new SimpleDateFormat("HHmmss").format(new Date()));
		reqHeadData.setSerialNo(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + Math.round(Math.random()*899999 + 100000));
		reqHeadData.setSignatureAlg("01");
		reqHeadData.setZipType("0");
		return reqHeadData;
	}
	
}
